#pragma once

#include "defines.h"
#include "platform/vk/vk_device_context.h"
#include "platform/vk/vk_swapchain.h"
#include "platform/vk/vk_graphics_pipeline.h"
#include "platform/vk/vk_texture.h"
#include "platform/vk/vk_texture_sampler.h"
#include "platform/vk/vk_texture_array.h"
#include "platform/vk/vk_uniform_buffer.h"

#include "scene/sprite2d.h"

namespace vkrender
{
    struct MVPUBO
    {
        glm::mat4 model;
        glm::mat4 view;
        glm::mat4 proj;
    };

    class SpriteRenderer
    {
    public:
        struct SimplePushConstantData
        {
            glm::vec2 offset;
            // alignas(16) glm::vec3 color;
        };
        MVPUBO ubo;

        std::shared_ptr<VulkanGraphicsPipeline> graphicsPipeline;
        VulkanSwapChain* swapchain;
        
        VkDescriptorPool descriptorPool;
        VkDescriptorSetLayout descriptorSetLayout;

        VkPipelineLayout pipelineLayout;

        std::vector<VkDescriptorSet> descriptorSets;
        // std::vector<VkCommandBuffer> commandBuffers;
        std::vector<VulkanUniformBuffer> uniformBuffers;

        std::shared_ptr<VulkanDeviceContext> context;

        std::shared_ptr<SpriteBuffer> spriteBuffer;

#if 0
        std::shared_ptr<VulkanTexture> texture;
#else
        std::shared_ptr<VulkanTextureArray> textures;
#endif
        std::shared_ptr<VulkanTextureSampler> sampler;

    public:
        SpriteRenderer(
            const std::shared_ptr<VulkanDeviceContext>& context,
            const std::shared_ptr<VulkanSwapChain>& swapchain
        );
        ~SpriteRenderer();
        
        void bind(uint32_t imageIndex, VkCommandBuffer cmd, const glm::mat4& proj, const glm::mat4& view);
        void draw(uint32_t imageIndex, VkCommandBuffer cmd, const SpriteQuad& sprite);
        void flush(VkCommandBuffer cmd);

        void adjustForSwapchain(const std::shared_ptr<VulkanSwapChain>& swapchain);
    private:
        void createDescriptorPool();
        void createDescriptorSetLayout();
        void createPipelineLayout();
        void createPipeline();
        void createDescriptorSets();
        void createUniformBuffers();

        void updateDescriptorSets();
        void updateUniformBuffer(uint32_t imageIndex,
            const glm::mat4& proj, const glm::mat4& view);
    };
}
